﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Threading;
using BaseHelper.Net;
using BaseHelper.Base;
using BaseHelper;

namespace DeviceSDK.LED.NuoWa.JT100
{
    public class JT100_SDK
    {
        private TcpClientHelper _tcp;
        private UdpHelper _udp;
        public SocketMode _socketMode = SocketMode.TCP;
        public int _udpPort = 12004;
        public string _remoteIP;

        private bool _isBusying = false;
        private int _timeoutSendFileSecond = 60;

        private int _fileBlockSize = 65500;//8100;
        private int _timeout = 2000;
        private CmdType _lastCmdType;
        private byte[] _lastReceiveBuffer;

        private CmdType _waitCmdType = CmdType.None;
        private StringBuilder _lastReceiveString;
        private object locker = new object();
        PackParse _mp = new PackParse();

        public static string Get_Error(int ret)
        {
            switch (ret)
            {
                case 0:
                    return "操作成功！";

                case 1:
                    return "操作失败！";

                case 2:
                    return "命令执行失败！";

                case 3:
                    return "保存节目单到磁盘失败！";

                case 4:
                    return "有素材文件格式不支持！";

                case -1:
                    return "操作失败！";

                default:
                    return "未知错误！";
            }
        }

        public bool IsConnected
        {
            get
            {
                if (_socketMode == SocketMode.TCP)
                {
                    if (_tcp.IsConnected)
                    {
                        int mills = 15000 / 10;     //15s等待时间
                        while (_isBusying && mills-- > 0)
                        {
                            Thread.Sleep(10);
                        }
                        return true;
                    }
                    return false;
                }
                else
                {
                    return false;
                }
            }
        }

        public bool Connect(string IP,int Port=5000)
        {
            _remoteIP = IP;
            if (_socketMode == SocketMode.TCP)
            {
                if (_tcp == null)
                {
                    _tcp = new TcpClientHelper();
                    _tcp.DataArriveEvent += new TcpClientHelper.DataArriveHandler(_socket_DataArreadEvent);
                    _tcp.DisconnectEvent+=new TcpClientHelper.DisconnectHandler(_tcp_DisconnectEvent);
                }
                return _tcp.Connect(IP, Port, _fileBlockSize+9);    //9是指令+ 数据+结束+CRC
            }
            else if(_socketMode==SocketMode.UDP)
            {
                if (_udp == null)
                {
                    _udp = new UdpHelper();
                    _udp.BeginReceive(Port);
                }
            }

            return false;
            
        }

        public void Close() 
        {
            if (_socketMode == SocketMode.TCP)
            {
                if (_tcp != null)
                    _tcp.Close();

            }
            else if (_socketMode == SocketMode.UDP)
            {
               
            }
        
        }

        private void _tcp_DisconnectEvent(string remoteIP)
        {
            _tcp = null;
        }

        public bool Poll()
        {
            long time=TimeHelper.ToTimeStamp();
            byte[] data = new byte[] { (byte)time, (byte)(time >> 8), (byte)(time >> 0x10), (byte)(time >> 0x18) };
            SendTcpData(0x00, data);
 
            if( WaitData(CmdType.HeartBeat,_timeout))
                return _lastReceiveBuffer[0] == 1;
            else 
                return false;

        }

        public void Pointer()
        {
            byte[] data = new byte[] {};
            SendTcpData(0xEA, data);

            //WaitData(_timeout);
        }

        public bool SetVirtualCheck(VirtualCheckState state, int second = 300000, int playbillID = 1)
        {
            //虚链接  0关闭1开启   秒低字节  秒高字节    节目编号
            byte[] data = new byte[] { (byte)state, (byte)second, (byte)((byte)second >> 8), (byte)playbillID };
            SendTcpData(0xF3, data);

            if (WaitData(CmdType.ReplySetVirtualCheck, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public bool Reboot()
        {
            SendTcpData(0x0D,null);

            if (WaitData(CmdType.ReplyResetDeviceResult, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public void GetCardState()
        {
            byte[] data = new byte[] { 0 };
            SendTcpData(0x01, data);

            //WaitData(_timeout);
        }

        public bool SetCardTime()
        {
            DateTime dt = DateTime.Now;
            byte[] data = new byte[] { (byte)dt.Year, (byte)(dt.Year >> 8), (byte)dt.Month, (byte)dt.Day, (byte)dt.Hour, (byte)dt.Minute, (byte)dt.Second };
            SendTcpData(0x09, data);
            if (WaitData(CmdType.ReplySetTimeResult, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }

        public string GetCardTime()
        {
            SendTcpData(0x01, null);

            if (WaitData(CmdType.ReplyDeviceStatus, _timeout))
            {
                string Year= ((int)_lastReceiveBuffer[0]+(int)(_lastReceiveBuffer[1]<<8)).ToString();
                string Month=_lastReceiveBuffer[2].ToString();
                string Day=_lastReceiveBuffer[3].ToString();
                string Hour=_lastReceiveBuffer[4].ToString();
                string Min=_lastReceiveBuffer[5].ToString();
                string Sec=_lastReceiveBuffer[6].ToString();
                return string.Format("{0}-{1}-{2} {3}:{4}:{5}",Year,Month,Day,Hour,Min,Sec);
            }
            else
                return null;

        }

        public bool SetScreenState(ScreenState state)
        {
            byte[] data = new byte[] { (byte)state };
            SendTcpData(0x05, data);


            if (WaitData(CmdType.ReplyOpenCloseScreenResult, _timeout))
            {
                Console.WriteLine(_lastReceiveBuffer.Length);
                return _lastReceiveBuffer[0] == 1;
            }
            else
                return false;
        }

        public ScreenState GetScreenState()
        {
            SendTcpData(0x01, null);

            if (WaitData(CmdType.ReplyDeviceStatus, _timeout))
                return _lastReceiveBuffer[8]==1?ScreenState.Open:ScreenState.Close;
            else
                return ScreenState.Fail;
        }

        public bool SetScreenLight(int val)
        {
            byte[] data = new byte[]{0x02,(byte)val};

            SendTcpData(0x07, data);

            if (WaitData(CmdType.ReplyBrightCtrlResult, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
            
        }

        public int GetScreenLight()
        {
            SendTcpData(0x01, null);
            if (WaitData(CmdType.ReplyDeviceStatus, _timeout))
                return (int)_lastReceiveBuffer[17] ;
            else
                return -1;
        }

        public string GetCardName()
        {
            byte[] data = new byte[] { 1 };
            SendTcpData(0x7e, data);

            if (WaitData(CmdType.ReplyCardNameOperate, _timeout) && _lastReceiveBuffer[0] == 1)
                return Encoding.UTF8.GetString(_lastReceiveBuffer,1,_lastReceiveBuffer.Length-1);
            else
                return null;

        }

        public bool SetCardName(string Name)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(Name);
            byte[] destinationArray = new byte[bytes.Length + 1];
            destinationArray[0] = 0;
            if (bytes.Length > 0)
                Array.Copy(bytes, 0, destinationArray, 1, bytes.Length);

            SendTcpData(0x7e, destinationArray);

            if (WaitData(CmdType.ReplyCardNameOperate, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }
        
        public bool CleanFile(CleanFileType type)
        {
            byte[] data = new byte[] {(byte)type};
            SendTcpData(0x7C, data); 
            

            if (WaitData(CmdType.ReplyClearFiles, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }


        public int Get_LedCheckErrorCount()
        {
            //byte[] data = new byte[] {};
            // SendTcpData((byte)CmdType.SetLedCheck, null);
            SendTcpData((byte)CmdType.SetLedCheck, null);


            if (WaitData(CmdType.ReplaySetLedCheck, 20000))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    int value = (int)_lastReceiveBuffer[1] + (int)(_lastReceiveBuffer[2] << 8);
                    return value;
                }
                else
                    return -1;
            }
            else
                return -1;
        }


        public string Get_LedCheckResult()
        {
            //byte[] data = new byte[] {};
            // SendTcpData((byte)CmdType.SetLedCheck, null);
            SendTcpData((byte)CmdType.ReadErrorPointInfo, null);

            if (WaitData(CmdType.ReplyReadErrorPointUintSize, 20000))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    int blockID=0;
                    int blockSize=(int)_lastReceiveBuffer[1] + (int)(_lastReceiveBuffer[2]<<8);
                    byte[] buffer=new byte[]{};
                  
                    while(true)
                    {
                        if(WaitData(CmdType.ReplyReadErrorPointPerInfo,3000))
                        {
                            blockID=(int)_lastReceiveBuffer[1] + (int)(_lastReceiveBuffer[2]<<8);
                            int thisBlockSize=_lastReceiveBuffer.Length-2;
                            byte[] thisBuffer=new byte[thisBlockSize];
                            byte[] tmp = new byte[buffer.Length+thisBlockSize] ;
                            Buffer.BlockCopy(buffer, 0, tmp, 0, buffer.Length);
                            Buffer.BlockCopy(_lastReceiveBuffer, 2, buffer, buffer.Length,thisBlockSize);
                            if(thisBlockSize<blockSize)
                            {
                                break;
                            }
                            SendTcpData((byte)CmdType.RecvErrorPointFileResult, new byte[]{(byte)blockID,(byte)(blockID>>8)});
                        }
                    }

                    return  Encoding.UTF8.GetString(buffer); 
                }
            }
            return "";
        }


        public Image GetScreenCap()
        {
            byte[] data = new byte[] { (byte)(_fileBlockSize), (byte)(_fileBlockSize >> 8) };

            _lastReceiveString = new StringBuilder();

            _waitCmdType = CmdType.ReplyGetCurrentDisplayScreenShot;
   
            SendTcpData(0x80, data);


            if (WaitData(CmdType.ReplyGetCurrentDisplayScreenShot, 10000))//_timeout
            {

                try
                {
                    MemoryStream ms = new MemoryStream();
                    ms.Write(_lastReceiveBuffer, 0, _lastReceiveBuffer.Length);

                    return Image.FromStream(ms);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("JT100_SDK.cs->GetScreenCap()", ex.Message + ex.StackTrace);
                }
                return null;
            }
            else
                return null;

        }

        public string GetPlaybillContent()
        {
            SendTcpData(0x3A, null);

            if (WaitData(CmdType.ReplyReadCurPlayAllContent, _timeout))
                return Encoding.UTF8.GetString(_lastReceiveBuffer,1,_lastReceiveBuffer.Length-1);//0x01 因为第一位被 播放编号占了
            else
                return null;
        }

        public bool SetPlaybill(int id)
        {
            byte[] data = new byte[] { (byte)id };
            SendTcpData(0x1B, data);

            if (WaitData(CmdType.ReplySetDisplayListResult, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }

        public bool SetInsertPlay()
        {
            string txt = "img=0,0,a.bmp,0,0,0\r\nimgparam=100";
            
            byte[] data = Encoding.UTF8.GetBytes(txt);

  
            SendTcpData(0x32, data);

            return true;

        }

        public bool SendPlaybill(int id,PlayBill playbill)
        {

            byte[] fileName;
            byte[] fileBody;
            foreach (object item in playbill.Items)
            {
              
                if (item is ItemBase)
                {
                    
                    ItemBase it = (ItemBase)item;
                    if (File.Exists(it.FilePath))
                    {

                        fileName = Encoding.UTF8.GetBytes(it.FileName);

                        if (item is ImageItem)
                        {
                            Image img = Image.FromFile(it.FilePath);
                            if (img.Width > it.Width || img.Height > it.Height)
                            {
                                System.Drawing.Imaging.ImageFormat format;
                                if (it.FileName.Contains(".jpg"))
                                    format = System.Drawing.Imaging.ImageFormat.Jpeg;
                                else if (it.FileName.Contains(".png"))
                                    format = System.Drawing.Imaging.ImageFormat.Png;
                                else if (it.FileName.Contains(".bmp"))
                                    format = System.Drawing.Imaging.ImageFormat.Bmp;
                                else
                                    format = System.Drawing.Imaging.ImageFormat.Png;

                                img = ImageHelper.GetThumb(img, it.Width, it.Height, false);
                                if(img!=null)
                                    fileBody = ImageHelper.ToBytes(img, format);
                                else
                                    fileBody = File.ReadAllBytes(it.FilePath);
                            }
                            else
                                fileBody = File.ReadAllBytes(it.FilePath);
                        }
                        else
                        {
                            fileBody = File.ReadAllBytes(it.FilePath);
                        }
                       // Console.WriteLine("--------" + it.FileName + "--------");

                        int tryTime = 2;
                        bool ret;
                        do
                        {
                            ret = SendFile(fileName, fileBody);
                        } while (!ret && tryTime-- > 0);

                        //如果item列表就一个，并且2次上传失败，则返回失败
                        if (playbill.Count == 1 && ret == false)
                        {
                            return false;
                        }
                    }
                }
            }

           // Console.WriteLine("--------play001.lst--------");
            fileName = Encoding.UTF8.GetBytes("play" + id.ToString().PadLeft(3,'0') + ".lst");
            fileBody = Encoding.UTF8.GetBytes(playbill.Create());

            if (SendFile(fileName, fileBody))
            {
                //Console.WriteLine("节目单发送成功！");
                return true;
            }
            else
            {
                //Console.WriteLine("节目单发送失败！");
            }
            return false;

        }

        public bool SendFile(byte[] fileName,byte[] fileBody)
        {


            int SeekIndex = 1;

            byte[] data=new byte[2+fileName.Length];
            data[0] = (byte)_fileBlockSize;
            data[1] = (byte)(_fileBlockSize >> 8);
            Array.Copy(fileName, 0,data, 2,fileName.Length);

            SendTcpData(0x11, data);
            DateTime dtTimeOut = DateTime.Now.AddSeconds(_timeoutSendFileSecond);

            if (WaitData(CmdType.ReplySetFileNameResult, 3000))
            {
                    if (_lastReceiveBuffer[0] == 1)
                    {
                        #region 文件发送
                        int blockCount = fileBody.Length / _fileBlockSize;
                        int blockLast = fileBody.Length % _fileBlockSize;

                        do
                        {
                            if (SeekIndex <= blockCount)
                            {
                                data = new byte[2 + _fileBlockSize];

                                data[0] = (byte)SeekIndex;
                                data[1] = (byte)(SeekIndex >> 8);

                                Array.Copy(fileBody, (SeekIndex-1) * _fileBlockSize, data, 2, _fileBlockSize);
                                SendTcpData(0x13, data);

                                if (WaitData(CmdType.ReplySendFileContent,(3000)))
                                {
                                    try
                                    {
                                        int retBlockCount = (int)_lastReceiveBuffer[0] + (int)(_lastReceiveBuffer[1] << 8);

                                        if (retBlockCount == SeekIndex)
                                        {
                                            if (_lastReceiveBuffer[2] == 0)
                                            {
                                                continue;
                                            }
                                            else
                                            {
                                                SeekIndex++;
                                                continue;
                                            }
                                        }
                                        else
                                            continue;
                                    }
                                    catch(Exception ex)
                                    {
                                        LogHelper.Debug("JT100_SDK.CS", "SendFile(),"+ ex.Message);
                                        return false;
                                    }
                                }
                                else
                                {
                                    //Console.WriteLine("bb");
                                    continue;
                                }
                            }


                            if (blockLast > 0)
                            {
                                data = new byte[2 + blockLast];
                                data[0] = (byte)SeekIndex;
                                data[1] = (byte)(SeekIndex >> 8);
                                Array.Copy(fileBody, _fileBlockSize * (SeekIndex - 1), data, 2, blockLast);
                                SendTcpData(0x13, data);
                            }

                            if (WaitData(CmdType.ReplySendFile, 1000))
                            {
                                return _lastReceiveBuffer[0] == 1;
                            }


                            if (WaitData(CmdType.ReplySendFileContent, (1000)) )
                            {
                                if (_lastReceiveBuffer[2] == 0)
                                    continue;
                                else if(_lastReceiveBuffer[2] == 1)
                                {
                                    SeekIndex++;
                                    data = new byte[2];
                                    data[0] = (byte)SeekIndex;
                                    data[1] = (byte)(SeekIndex >> 8);
                                    SendTcpData(0x13, data);

                                }
                            }
                        } while (SeekIndex <= (blockCount + 1) && DateTime.Now <= dtTimeOut);

                        //发送连续失败，超时了
                        if (DateTime.Now > dtTimeOut)
                        {
                            LogHelper.Debug("JT100_SDK.CS", "SendFile(),DateTime.Now > dtTimeOut," + DateTime.Now.ToString());
                        }

                        #endregion
                    }
                    else if (_lastReceiveBuffer[0] == 2)
                    {
                        return true;
                    }
                    else if (_lastReceiveBuffer[0] == 0)
                    {
                        return false;
                    }
                
            }
            return false;
           
        }

        private bool WaitData(CmdType CmdType,int mills)
        {
          
            mills /= 10;
            while (_lastCmdType != CmdType && mills-- > 0)
            {
                Thread.Sleep(10);
            }
            _isBusying = false;
            if (_lastCmdType == CmdType)
                return true;
            else
                return false;
        }

        private void SendTcpData(byte packType, byte[] data)
        {
            if (_tcp == null)
                return;
            lock (locker)
            {
                while (_isBusying)
                {
                    Thread.Sleep(100);
                }

                _isBusying = true;
            }
            
            _lastCmdType = CmdType.None;
            _lastReceiveBuffer = new byte[] { };
            //_waitCmdType = (CmdType)packType;

            byte[] packData = _mp.MakePackage(_socketMode, packType, data);
            if(_socketMode==SocketMode.TCP)
                _tcp.SendBytes(packData);
            //else if(_socketMode==SocketMode.UDP)
            //    _udp.SendBytes(_remoteIP, _udpPort, packData);


        }


        private void _socket_DataArreadEvent(string remoteIp,byte[] buffer, int len)
        {
          
            //if (_lastCmdType != _waitCmdType)
            //    return;
            lock (locker)
            {
                try
                {

                    //string dat2a = BitConverter.ToString(buffer, 0, len).Replace("-", " ");
                    //Console.WriteLine("【返回】" + dat2a);

                    if (_waitCmdType == CmdType.ReplyGetCurrentDisplayScreenShot)
                    {
                        string data = BitConverter.ToString(buffer, 0, len).Replace("-", "");
                        _lastReceiveString.Append(data);

                        if (len < _fileBlockSize && data.Substring(data.Length - 6, 2) == "CC")
                        {
                            string[] fileBlocks = _lastReceiveString.ToString().Split(new string[] { "AAFFFF81" }, StringSplitOptions.RemoveEmptyEntries);

                            foreach (string block in fileBlocks)
                            {
                                byte[] cutBuffer;
                                string new_block;
                                int blockNum = 0;

                                cutBuffer = BitHelper.StrToToHexByte(block);
                                blockNum = (int)cutBuffer[0] + (int)(cutBuffer[1] << 8);
                              
                                if (true)
                                {
                                    string fileBody = "AAFFFF81" + block;//  //10=4为块号+6位结尾;
                                    byte[] fileBytes = BitHelper.StrToToHexByte(fileBody);
                                    len = fileBytes.Length;
                                    CmdType _clastCmdType = _mp.DealPackage(_socketMode, ref fileBytes, ref len);

                                    cutBuffer = new byte[fileBytes.Length - 2];
                                    Array.Copy(fileBytes, 2, cutBuffer, 0, cutBuffer.Length);
                                }
                                else
                                {

                                    if (block.Substring(block.Length - 6, 2) == "CC")
                                        new_block = block.Substring(4, block.Length - (4 + 6));
                                    else
                                        new_block = block.Substring(4, block.Length - 4);

                                    new_block = new_block.Replace("EE0A", "AA").Replace("EE0C", "CC").Replace("EE0E", "EE");
                                    cutBuffer = BitHelper.StrToToHexByte(new_block);
                                }

                                byte[] fileContact = new byte[_lastReceiveBuffer.Length + cutBuffer.Length];
                                Array.Copy(_lastReceiveBuffer, 0, fileContact, 0, _lastReceiveBuffer.Length);
                                Array.Copy(cutBuffer, 0, fileContact, _lastReceiveBuffer.Length, cutBuffer.Length);
                                _lastReceiveBuffer = fileContact;
                            }

                            _lastCmdType = CmdType.ReplyGetCurrentDisplayScreenShot;

                            return;
                        }

                        Thread.Sleep(5);
                    }
                    else
                    {
                        _lastCmdType = _mp.DealPackage(_socketMode, ref buffer, ref len);
                        _lastReceiveBuffer = buffer;
                    }
                }
                catch (Exception ex)
                {
                }

            }



            //Console.WriteLine("buffer:" + buffer.Length.ToString() + "  " + DateTime.Now.ToString());
            //Console.Write("cmd:" + _lastCmdType.ToString() + " ret:");
            //////foreach (byte b in buffer)


            //for (int i = 0; i < len; i++)
            //{

            //    Console.Write(buffer[i] + " ");
            //}

            //Console.Write("\r\n");
        }

    }
}
